using System;
using Gtk;
using NetworkCommsDotNet;
using System.Collections.Generic;
using JmShared;
using DPSBase;
using System.Linq;
using System.Net;
using MessageType = JmShared.MessageType;

namespace JiveMessengerLinux
{
	public static class Client
	{
	    public static TextTag GreyUser { get; set; }
	    public static TextTag GreenUser { get; set; }
        public static TextTag RedUser { get; set; }
	    public static Dictionary<string, UserInfo> ConnectedClients { get; set; }
		public static UserInfo CurrentUserInfo = null;
		public static ConnectionInfo MasterConnectionInfo { get; set; }
		public static bool IsLoggedIn { get; set; }
		public static bool IsAfk { get; set; }
		public static bool IsBusy { get; set; }
		public static string LastConnectedUserName { get; set; }
		public static event EventHandler<WriteMessageEventArgs> ProcessMessageEvent;
		public static event EventHandler<EventArgs> ClientDisconnectedEvent;

        public static Dictionary<string,Gtk.TextTag> TextTags{ get; set; }
        public static Dictionary<string,int> TextTagCount {get;set;}

	    static Client()
	    {
	        GreyUser = new TextTag("GreyUser");
	        Gdk.Color grey = Gdk.Color.Zero;
            Gdk.Color.Parse("#696969", ref grey);
            GreyUser.ForegroundGdk = grey;
	        GreyUser.FontDesc.Size = GreyUser.FontDesc.Size-4;
	        GreyUser.Weight = Pango.Weight.Light;
	        GreyUser.Style = Pango.Style.Normal;

	        GreenUser = new TextTag("GreenUser");
	        Gdk.Color green = Gdk.Color.Zero;
            Gdk.Color.Parse("#008000", ref green);
            GreenUser.ForegroundGdk = green;

            GreenUser.Weight = Pango.Weight.Light;
            GreenUser.Style = Pango.Style.Normal;

	        RedUser = new TextTag("RedUser");
	        Gdk.Color red = Gdk.Color.Zero;
	        Gdk.Color.Parse("#800000", ref red);
            RedUser.ForegroundGdk = red;
            RedUser.Weight = Pango.Weight.Light;
            RedUser.Style = Pango.Style.Normal;
	    }

	    public static void Reset()
		{
			ConnectedClients = new Dictionary<string, UserInfo>();
		}

		private static void ProcessMessage (PacketHeader packetHeader, Connection connection, ChatMessage incomingObject)
		{
		    connection.SendObject("reply", "1");
			WriteMessageEventArgs arg = new WriteMessageEventArgs(null,incomingObject);
			ProcessMessageEvent(null,arg);
		}

		private static void client_OnDisconnected (Connection connection)
		{
			NetworkComms.RemoveGlobalConnectionCloseHandler(client_OnDisconnected);
			NetworkComms.RemoveGlobalIncomingPacketHandler("ChatMessage");
			ClientDisconnectedEvent(null,null);
		}

        public static Gtk.TextTag GetTextTagForUser(UserInfo user,int num)
        {

            Gtk.TextTag tt = new Gtk.TextTag(user.UserID+num);
            Gdk.Color parsedColor = new Gdk.Color();
           
              string color = user.Color.StartsWith("#") ? user.Color : "#" + user.Color;
            if (Gdk.Color.Parse(color, ref parsedColor))
            {
                tt.ForegroundGdk = parsedColor;
            }
            tt.Weight = ParseFontWeigth(user.FontStyle);
            tt.Style = ParseFontStyle(user.FontStyle);

            return tt;
        }
       
        public static Pango.Weight ParseFontWeigth(string fontStyle)
        {
            Pango.Weight w = Pango.Weight.Normal;;
            switch (fontStyle)
            {
                case "Light":
                    w = Pango.Weight.Light;
                    break;
                    case "Regular":
                    w = Pango.Weight.Normal;
                    break;
                    case "Italic":
                    w = Pango.Weight.Normal;
                    break;
                    case "Semibold":
                    w = Pango.Weight.Semibold;
                    break;
                    case "Bold":
                    w = Pango.Weight.Bold; 
                    break;
                    case "Bold Italic":
                    w = Pango.Weight.Bold;
                    break;
                    case "Light Oblique":
                    w = Pango.Weight.Light;
                    break;
                    case "Semibold Oblique":
                    w = Pango.Weight.Semibold;
                    break;

            }
            return w;
        }
        public static Pango.Style ParseFontStyle(string fontStyle)
        {
            Pango.Style s = Pango.Style.Normal;
            switch (fontStyle)
            {
                case "Light":
                    s = Pango.Style.Normal;
                    break;
                    case "Regular":
                    s = Pango.Style.Normal;
                    break;
                    case "Italic":
                    s = Pango.Style.Italic;
                    break;
                    case "Semibold":
                    s = Pango.Style.Normal;
                    break;
                    case "Bold":
                    s = Pango.Style.Normal;
                    break;
                    case "Bold Italic":
                    s = Pango.Style.Italic;
                    break;
                    case "Light Oblique":
                    s = Pango.Style.Oblique;
                    break;
                    case "Semibold Oblique":
                    s = Pango.Style.Oblique;
                    break;

            }
            return s;
        }
		/// <summary>
		/// Connects to the server
		/// </summary>
		/// <returns></returns>
		public static bool Connect(bool isReconnect)
		{
			try
			{
				if (MasterConnectionInfo != null)
				{
					if (MasterConnectionInfo.ConnectionState == ConnectionState.Established)
						TCPConnection.GetConnection(Client.MasterConnectionInfo).CloseConnection(false);
					
					MasterConnectionInfo = null;
				}
				if (String.IsNullOrEmpty(StaticSettings.Server))
					return false;
				IPAddress[] serverAddresses = Dns.GetHostAddresses(StaticSettings.Server);
				
				if (serverAddresses.Length == 0)
				{
//					MessageBox.Show("Could not resolve server");
					return false;
				}
				MasterConnectionInfo = new ConnectionInfo(serverAddresses[0].ToString(), 36410);
				NetworkComms.Logger.Info(String.Format("Server address set to {0}", serverAddresses[0]));
				
				var dataProcessors = new List<DataProcessor>
				{
					// DPSManager.GetDataProcessor<SevenZipLZMACompressor.LZMACompressor>(),
					DPSManager.GetDataProcessor<RijndaelPSKEncrypter>()
				};
				var dataProcessorOptions = new Dictionary<string, string>();
                NetworkComms.EnablePacketCheckSumValidation = true;
				RijndaelPSKEncrypter.AddPasswordToOptions(dataProcessorOptions, "fg342ssdfs43232fdfgdg3452fdsgbvcvcblkiuyoaxc");
				DataSerializer dataSerializer = DPSManager.GetDataSerializer<ProtobufSerializer>();
				NetworkComms.DefaultSendReceiveOptions = new SendReceiveOptions(dataSerializer, dataProcessors, dataProcessorOptions);
				NetworkComms.ConnectionEstablishTimeoutMS = 5000;
				NetworkComms.ConnectionAliveTestTimeoutMS = 2000;
				NetworkComms.Logger.Info("NetworkComms options set successfully");
				//NetworkComms.Logger.Info("masterconnectioninfo set successfully");
				NetworkComms.AppendGlobalIncomingPacketHandler<ChatMessage>("ChatMessage", ProcessMessage);
				NetworkComms.AppendGlobalConnectionCloseHandler(client_OnDisconnected);
				NetworkComms.IgnoreUnknownPacketTypes = true;
				TCPConnection.GetConnection(Client.MasterConnectionInfo).EstablishConnection(); //Connect
				
				//Thread.Sleep(500);
				
				if (MasterConnectionInfo.ConnectionState != ConnectionState.Established)
				{
//					this.Dispatcher.Invoke((Action)(() =>
//					                                {
//						this.loginWindow.txtBlockError.Text = "Not Connected! ";
//						this.loginWindow.bnLogin.IsEnabled = true;
//					}));
					return false;
				}
				
//				if (this.Dispatcher.CheckAccess())
//					this.AvatarButtonGrid.Children.Clear();
//				else
//					this.Dispatcher.Invoke((Action)(() => this.AvatarButtonGrid.Children.Clear()));
				
				UserInfo user = new UserInfo()
				{ 
					UserName = StaticSettings.Username,
					ID = StaticMethods.GetPhysicalAddresses()[0].GetHashCode().ToString("x2"),
//					FontStyle = Properties.Settings.Default.Font.Style.ToString(),
//					FontName = Properties.Settings.Default.Font.Name,
//					Color = StaticMethods.ColorToHexString(Properties.Settings.Default.Color.Name),
					ClientStatus = ClientStatus.Available,
					ClientVersion = StaticSettings.VersionNumber//Assembly.GetExecutingAssembly().GetName().Version.ToString()
				};
				ChatMessage msg = new ChatMessage
				{
					MessageType = MessageType.Login,
					Message = StaticMethods.LoginInfoToString(new LoginInfo
					                                          {
						Username = StaticSettings.Username,
						Password = StaticSettings.Password
					}),
					Sender = user
				};
				CurrentUserInfo = user;
				SendMessage(msg);
				return true;
			}
			catch (Exception err)
			{
				if (!isReconnect)
				{
					NetworkComms.Logger.ErrorException("Exeception in login", err);
					Gtk.Application.Invoke(delegate {
					MessageBox.Show(err.Message);
					});
					//NetworkComms.Logger.Error(err.ToString());
				}
				return false;
			}
		}

		/// <summary>
		/// Sends the chatmessage to the server
		/// </summary>
		/// <param name="msg"></param>
		public static bool SendMessage(ChatMessage msg)
		{
            if (MasterConnectionInfo == null)
                return false;
            if (MasterConnectionInfo.ConnectionState != ConnectionState.Established)
                return false;
            bool receiptOk = msg.MessageType != MessageType.Message && msg.MessageType != MessageType.PM;
            try
            {
                if (msg.MessageType == MessageType.Message || msg.MessageType == MessageType.PM)
                    receiptOk = ((TCPConnection.GetConnection(MasterConnectionInfo).SendReceiveObject<string>("ChatMessage", "receipt", 2000, msg)) == "1");
                else
                    TCPConnection.GetConnection(MasterConnectionInfo).SendObject("ChatMessage", msg);
            }
            catch (CommsException err)
            {
                //NetworkComms.Logger.ErrorException("Error writing message", err);
                receiptOk = false;
            }
            return receiptOk;
		}
		public static void SendStatusMessage(MessageType mt, string message)
		{
			ChatMessage msg = new ChatMessage {Sender = CurrentUserInfo, MessageType = mt, Message = message};
			SendMessage(msg);
		}
		
		public static void SendStatusMessage(MessageType mt, string message,UserInfo[] targets)
		{
			ChatMessage msg = new ChatMessage { Sender = CurrentUserInfo, MessageType = mt, Message = message, UserInfo = targets};
			SendMessage(msg);
		}
		/// <summary>
		/// Broadcast your custom emoticons
		/// </summary>
		public static void BroadcastEmoticons()
		{
			SendStatusMessage(MessageType.BroadcastEmoticons, StaticMethods.ListToString(StaticSettings.CustomEmoticons.Keys.ToList()));
		}
		/// <summary>
		/// Broadcast your custom emoticons
		/// </summary>
		public static void BroadcastEmoticons(UserInfo target)
		{
			SendStatusMessage(MessageType.BroadcastEmoticons, StaticMethods.ListToString(StaticSettings.CustomEmoticons.Keys.ToList()),new[]{target});
		}
		/// <summary>
		/// Broadcast your custom emoticons
		/// </summary>
		public static void BroadcastEmoticons(UserInfo[] targets)
		{
			SendStatusMessage(MessageType.BroadcastEmoticons, StaticMethods.ListToString(StaticSettings.CustomEmoticons.Keys.ToList()),targets);
		}
		
	}
}

